package com.example.project.projectspringcloud.service.impl.user;

import com.example.project.projectspringcloud.common.Constants;
import com.example.project.projectspringcloud.common.OperationException;
import com.example.project.projectspringcloud.dao.user.RelationRoleUserMapper;
import com.example.project.projectspringcloud.dao.user.UserMapper;
import com.example.project.projectspringcloud.dao.user.UserProfileMapper;
import com.example.project.projectspringcloud.dao.video.VideoMapper;
import com.example.project.projectspringcloud.entity.Page;
import com.example.project.projectspringcloud.entity.user.RelationRoleUser;
import com.example.project.projectspringcloud.entity.user.Role;
import com.example.project.projectspringcloud.entity.user.User;
import com.example.project.projectspringcloud.entity.user.UserProfile;
import com.example.project.projectspringcloud.entity.user.pojo.UserPojo;
import com.example.project.projectspringcloud.service.BaseService;
import com.example.project.projectspringcloud.service.user.UserService;
import com.example.project.projectspringcloud.utils.StringUtil;
import com.example.project.projectspringcloud.utils.WebUtil;
import com.github.pagehelper.PageHelper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.*;

/**
 * User Service
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl extends BaseService<User, UserMapper> implements UserService, UserDetailsService {

    @Autowired
    private RelationRoleUserMapper relationRoleUserMapper;

    @Autowired
    private VideoMapper videoMapper;

    @Autowired
    private UserProfileMapper userProfileMapper;

    @Override
    public User get(User user) {
        return super.mapper.selectOne(user);
    }

    @Override
    public User getWithPrivate(User record) {
        return super.mapper.selectOneWithPrivate(record);
    }

    @Override
    public List<User> list(Page page, User user) {
        return super.list(page, user);
    }

    @Override
    public List<User> listWithPrivate(Page page, User user) {
        if (page != null) {
            PageHelper.startPage(page.getPageNum(), page.getPageSize());
        }
        return super.mapper.selectAllWithPrivate(user);
    }

    @Override
    public boolean delete(Integer[] ids) {
        for (Integer userId : ids) {
            videoMapper.deleteByUser(userId);
            relationRoleUserMapper.deleteByUser(userId);
        }
        return super.mapper.deleteByArrayPrimaryKey(ids) > 0;
    }

    @Override
    public boolean save(User user) {
        // 如果传来的参数包含密码, 则加密密码后更新
        if (StringUtils.isNotBlank(user.getPwd())) {
            user.setPwd(StringUtil.md5encode(user.getPwd()));
        }

        super.save(user);

        if (user.getRoles() != null) {
            // update current user permission
            RelationRoleUser entity = new RelationRoleUser();
            entity.setUser(user.getId());
            int deleteResult = relationRoleUserMapper.deleteByUser(user.getId());

            List<RelationRoleUser> entities = new ArrayList<>();
            if (user.getRoles() != null) {
                user.getRoles().forEach(role -> {
                    if (role.getId() != null) {
                        RelationRoleUser rru = new RelationRoleUser();
                        rru.setUser(user.getId());
                        rru.setRole(role.getId());
                        entities.add(rru);
                        relationRoleUserMapper.insert(rru);
                    }
                });
            }
        }

        // 如果是当前登录用户执行的更新, 就是用户更新了自己的个人信息
        if (user.getId().equals(WebUtil.getCurrentUser().getId())) {
            // 用户信息保存完成之后，更新登录用户
            UserDetails userDetails = loadUserByUsername(WebUtil.getCurrentUser().getAccount());
            SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(userDetails, userDetails.getAuthorities(), userDetails.getAuthorities()));
        }
        return true;
    }

    @Override
    public boolean saveAbsolute(User user) {
        super.saveAbsolute(user);
        // 如果是当前登录用户执行的更新, 就是用户更新了自己的个人信息
        if (user.getId().equals(WebUtil.getCurrentUser().getId())) {
            // 用户信息保存完成之后，更新登录用户
            UserDetails userDetails = loadUserByUsername(WebUtil.getCurrentUser().getAccount());
            SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(userDetails, userDetails.getAuthorities(), userDetails.getAuthorities()));
        }
        return true;
    }


    @Override
    public boolean changeShow(User user) throws OperationException {
        String filtrate = user.getFiltrate();
        user = super.mapper.selectOne(user);
        if (user != null) {
            user.setFiltrate(filtrate);
            if (super.mapper.updateByPrimaryKeySelective(user) < 1) {
                return false;
            }
        } else {
            return false;
        }
        return true;
    }

    private User add(UserPojo userPojo) {
        User newUser = new User();
        // 昵称
        newUser.setNickname(StringUtils.isBlank(userPojo.getNickname()) ? userPojo.getMobile() : userPojo.getNickname());
        // 手机
        newUser.setMobile(userPojo.getMobile());
        // 账号
        newUser.setAccount(userPojo.getMobile());
        // 微信号
        newUser.setWechat(userPojo.getWechat());
        // 密码
        newUser.setPwd(StringUtil.md5(userPojo.getPassword()));
        // 用户类型： 普通用户
        newUser.setType(2);
        // 默认性别女
        newUser.setGender(0);
        // 用户可用状态
        newUser.setStatus(1);
        // 创建时间
        newUser.setCreateDate(new Date());
        // 插入
        super.mapper.insert(newUser);
        // 添加角色
        RelationRoleUser rru = new RelationRoleUser();
        rru.setRole(2);
        rru.setUser(newUser.getId());
        relationRoleUserMapper.insert(rru);
        return newUser;
    }

    @Override
    public boolean register(UserPojo userPojo) throws OperationException {
        // 查看手机是否注册
        String mobile = userPojo.getMobile();
        User entity = new User();
        entity.setMobile(mobile);
        entity = super.mapper.selectOneWithPrivate(entity);
        Optional<User> user = Optional.ofNullable(entity);
        // 用户手机号存在
        if (user.isPresent()) {
            throw new OperationException(Constants.Tip.ACCOUNT_MOBILE_EXIST);
        }
        // 手机号不存在
        else {
            // 如果有第三方令牌
            if (StringUtils.isNotBlank(userPojo.getOpenID())) {
                UserProfile userProfile = new UserProfile();
                userProfile.setOpenId(userPojo.getOpenID());
                userProfile = userProfileMapper.selectOne(userProfile);
                Optional<UserProfile> existUserProfile = Optional.ofNullable(userProfile);
                // 如果存在第三方信息, 关联
                if (existUserProfile.isPresent()) {
                    User newUser = add(userPojo);
                    userProfile.setUserId(newUser.getId());
                    userProfileMapper.updateByPrimaryKeySelective(userProfile);
                }
                // 如果没有
                else {
                    add(userPojo);
                }
            }
            // 如果没有第三方令牌
            else {
                add(userPojo);
            }
        }

        return true;
    }

    @Override
    public void retrieve(UserPojo userPojo) throws OperationException {
        // 查看手机是否注册
        String mobile = userPojo.getMobile();
        User entity = new User();
        entity.setMobile(mobile);
        entity = super.mapper.selectOneWithPrivate(entity);
        Optional<User> user = Optional.ofNullable(entity);
        // 用户手机已注册, 可以重置密码
        if (user.isPresent()) {
            entity.setPwd(StringUtil.md5(userPojo.getPassword()));
            super.mapper.updateByPrimaryKeySelective(entity);
        } else {
            throw new OperationException(Constants.Tip.ACCOUNT_MOBILE_EXIST);
        }
    }

    @Override
    public List<User> list(Set<Integer> dataIds, Integer contentType) {
        return super.mapper.selectAllByIdsAndType(dataIds, contentType);
    }

    @Override
    public boolean changePassword(User user, String password, String passwords) throws OperationException {
        if (ObjectUtils.isEmpty(user) || user.getId() == null) {
            throw new OperationException(Constants.SystemMessage.SYSTEM_ERROR);
        }

        if (StringUtils.isBlank(password)) {
            throw new OperationException(Constants.Tip.PASSWORD_FORMAL_ERROR);
        }

        if (!password.equals(passwords)) {
            throw new OperationException(Constants.Tip.THE_TWO_PASSWORD_ARE_DIFFERENT);
        }

        user.setPwd(StringUtil.md5encode(passwords));

        return super.mapper.updatePassword(user) > 0;
    }

    /**
     * spring-boot-security 用户验证
     *
     * @param account
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {
        User user = new User();
        user.setAccount(account);
        user = super.mapper.selectOneWithPrivate(user);
        if (user == null) {
            throw new UsernameNotFoundException(Constants.Message.USER_ACCOUNT_NOT_FOUND);
        }

        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        Set<Integer> roleLevelSet = new HashSet<>();

        RelationRoleUser relationRoleUser = new RelationRoleUser();
        relationRoleUser.setUser(user.getId());
        List<RelationRoleUser> relationRoleUsers = relationRoleUserMapper.selectAllByUser(relationRoleUser);
        List<Role> roles = new ArrayList<>();
        relationRoleUsers.forEach(t -> {
            authorities.add(new SimpleGrantedAuthority(t.getUserRole().getName()));
            roles.add(t.getUserRole());
            if (t.getUserRole().getLevel() != null) {
                roleLevelSet.add(t.getUserRole().getLevel());
            }
        });

        // cache user info in Spring Security
        com.example.project.projectspringcloud.entity.UserDetails customUserDetails = new com.example.project.projectspringcloud.entity.UserDetails(user.getAccount(), user.getPwd(), true);
        customUserDetails.setMobile(user.getMobile());
        customUserDetails.setAccount(user.getAccount());
        customUserDetails.setNickname(user.getNickname());
        customUserDetails.setGender(user.getGender());
        customUserDetails.setId(user.getId());
        customUserDetails.setPortrait(user.getPortrait());
        customUserDetails.setWechat(user.getWechat());

        customUserDetails.setAuthorities(authorities);
        customUserDetails.setRoleLevels(roleLevelSet.toArray(new Integer[0]));
        customUserDetails.setRoles(roles);
        Optional<Integer> maxRoleLevel = roleLevelSet.stream().max(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });

        customUserDetails.setMaxRoleLevel(maxRoleLevel.isPresent() ? maxRoleLevel.get() : 0);
        return customUserDetails;
    }
}
